package eu.telecombretagne.rsm.gui.frames;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JInternalFrame;
import javax.swing.JMenuBar;
import javax.swing.JFrame;

import eu.telecombretagne.rsm.gui.NameConsts;

import java.awt.event.*;
import java.awt.*;
import java.beans.PropertyVetoException;

public class DesktopFrame extends JFrame implements ActionListener {
	
	private static final long serialVersionUID = 1864412180054625462L;

	private JDesktopPane desktop;
	
	private static LogInternalFrame logInternalFrame;
	private static AutomateInternalFrame automateInternalFrame;
	private static NetworkInternalFrame networkInternalFrame;
	
	/**
	 * The constructor of the DesktopFrame.
	 */
	public DesktopFrame(){
		super(NameConsts.NETWORKEMULATOR);
		
		setIconImage(new ImageIcon(this.getClass().getResource(NameConsts.GFXMAIN)).getImage());
		
		Integer inset = 50;
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		setBounds(inset, inset, screenSize.width - inset*2, screenSize.height - inset*2);
		
		desktop = new JDesktopPane();
		
		addInternalFrame(new NetworkInternalFrame());
		addInternalFrame(new LogInternalFrame());
		addInternalFrame(new AutomateInternalFrame());
		
		setContentPane(desktop);
		setJMenuBar(createMenuBar());
		
		desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
		
		writeLogInfo(NameConsts.EMULATORISREADY);
	}
	
	private JMenuBar createMenuBar(){
		JMenuBar menuBar = new JMenuBar();
				
		JButton networkFrame = new JButton(NameConsts.NETWORKCONTROL);
		networkFrame.setActionCommand("btnNetworkFrame");
		networkFrame.addActionListener(this);
		networkFrame.setIcon(new ImageIcon(this.getClass().getResource(NameConsts.GFXCONTROL)));
		
		JButton automataFrame = new JButton(NameConsts.AUTOMATEGRAPH);
		automataFrame.setActionCommand("btnAutomataFrame");
		automataFrame.addActionListener(this);
		automataFrame.setIcon(new ImageIcon(this.getClass().getResource(NameConsts.GFXAUTOMATE)));
		
		JButton logFrame = new JButton(NameConsts.SYSTEMLOG);
		logFrame.setActionCommand("btnLogFrame");
		logFrame.addActionListener(this);
		logFrame.setIcon(new ImageIcon(this.getClass().getResource(NameConsts.GFXLOG)));
		
		menuBar.add(networkFrame);
		menuBar.add(automataFrame);
		menuBar.add(logFrame);
		
		return menuBar;
    }
	
	private <T extends JInternalFrame> void addInternalFrame(T pInternalFrame){
		if(pInternalFrame instanceof NetworkInternalFrame){
			networkInternalFrame = (NetworkInternalFrame) pInternalFrame;
		} else if(pInternalFrame instanceof LogInternalFrame){
			logInternalFrame = (LogInternalFrame) pInternalFrame;
		} else if(pInternalFrame instanceof AutomateInternalFrame){
			automateInternalFrame = (AutomateInternalFrame) pInternalFrame;
		}
		
		pInternalFrame.setVisible(true);
		desktop.add(pInternalFrame);
	}
	
	private static void createAndShowGUI(){
		JFrame.setDefaultLookAndFeelDecorated(true);
		
		DesktopFrame frame = new DesktopFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		frame.setVisible(true);
	}
	
	/**
	 * Writes a line in the emitter log.
	 * @param pLogLine A string line to be written.
	 */
	public static void writeLogEmitter(String pLogLine){
		if(logInternalFrame != null)
			logInternalFrame.appendLineEmitterToLog(pLogLine);
	}
	
	/**
	 * Writes a line in the error log.
	 * @param pLogLine A string line to be written.
	 */
	public static void writeLogError(String pLogLine){
		if(logInternalFrame != null)
			logInternalFrame.appendLineErrorToLog(pLogLine);
	}
	
	/**
	 * Writes a line in the info log.
	 * @param pLogLine A string line to be written.
	 */
	public static void writeLogInfo(String pLogLine){
		if(logInternalFrame != null)
			logInternalFrame.appendLineInfoToLog(pLogLine);
	}
	
	/**
	 * Writes a line in the network log.
	 * @param pLogLine A string line to be written.
	 */
	public static void writeLogNetwork(String pLogLine){
		if(logInternalFrame != null)
			logInternalFrame.appendLineNetworkToLog(pLogLine);
	}
	
	/**
	 * Writes a line in the receiver log.
	 * @param pLogLine A string line to be written.
	 */
	public static void writeLogReceiver(String pLogLine){
		if(logInternalFrame != null)
			logInternalFrame.appendLineReceiverToLog(pLogLine);
	}
	
	/**
	 * Shows an automate state of the receiver.
	 * @param pState An automata state to be shown.
	 */
	public static void showAutomataStateReceiver(String pState){
		if(automateInternalFrame != null)
			automateInternalFrame.setAutomateStateReceiver(pState);
	}
	
	/**
	 * Shows an automate state of the emitter.
	 * @param pState An automata state to be shown.
	 */
	public static void showAutomataStateEmitter(String pState){
		if(automateInternalFrame != null)
			automateInternalFrame.setAutomateStateEmitter(pState);
	}

	@Override
	public void actionPerformed(ActionEvent actionEvent) {
		if("btnNetworkFrame".equals(actionEvent.getActionCommand())){
			switchInternalFrameOpenedClosed(networkInternalFrame);
			
		} else if("btnAutomataFrame".equals(actionEvent.getActionCommand())){
			switchInternalFrameOpenedClosed(automateInternalFrame);
			
		} else if("btnLogFrame".equals(actionEvent.getActionCommand())){
			switchInternalFrameOpenedClosed(logInternalFrame);
			
		}
	}
	
	private <T extends JInternalFrame> void switchInternalFrameOpenedClosed(T pInternalFrame){
		try {
			if(pInternalFrame.isClosed()){
				setInternalFrameClosed(pInternalFrame, false);
			} else {
				setInternalFrameClosed(pInternalFrame, true);
			}
		} catch (PropertyVetoException e) {
			writeLogError(NameConsts.INTERFACEERRORFORTHEFRAME + pInternalFrame.getTitle());
		}
	}
	
	private <T extends JInternalFrame> void setInternalFrameClosed(T pInternalFrame, Boolean pClosed) throws PropertyVetoException{
		if(pClosed){
			pInternalFrame.setClosed(true);
			
		} else {
			if(pInternalFrame.isClosed()){
				pInternalFrame.setClosed(false);
				pInternalFrame.setVisible(true);
				desktop.add(pInternalFrame);
			}
			
			pInternalFrame.setSelected(true);
		}
	}
	
	public static void main(String[] args){
		javax.swing.SwingUtilities.invokeLater(new Runnable(){
			public void run(){
				createAndShowGUI();
			}
		});
	}
}